// 完整校园图书借阅系统（while/do-while循环+流程控制）
import scala.collection.mutable
import scala.util.control.Breaks._
import scala.util.Random

object LibrarySystem extends App {
  // 1. 定义核心数据结构
  case class Book(
                   id: String,
                   title: String,
                   author: String,
                   totalCopies: Int,
                   var availableCopies: Int  // 可变：库存会更新
                 )

  case class BorrowRecord(
                           recordId: String,
                           readerId: String,
                           bookId: String,
                           borrowDate: String,
                           dueDate: String,
                           var renewCount: Int,  // 可变：续借次数会更新
                           var returnDate: Option[String] = None  // 可变：归还时赋值
                         )

  case class Reader(
                     id: String,
                     name: String,
                     var unpaidFines: Double = 0.0  // 可变：罚款会累加
                   )

  // 2. 初始化数据（模拟数据库）
  // 图书库（ID -> 图书）
  val books = mutable.Map[String, Book](
    "B001" -> Book("B001", "Scala编程", "Martin Odersky", 5, 3),
    "B002" -> Book("B002", "Java编程思想", "Bruce Eckel", 3, 1),
    "B003" -> Book("B003", "数据结构与算法", "Mark Allen Weiss", 4, 4),
    "B004" -> Book("B004", "机器学习实战", "Peter Harrington", 2, 0),
    "B005" -> Book("B005", "深入理解计算机系统", "Randal E. Bryant", 5, 5)
  )

  // 读者库（ID -> 读者）
  val readers = mutable.Map[String, Reader](
    "R001" -> Reader("R001", "张三", 15.0),    // 有15元未缴罚款
    "R002" -> Reader("R002", "李四"),         // 无罚款
    "R003" -> Reader("R003", "王五", 60.0)    // 有60元未缴罚款（超上限）
  )

  // 借阅记录（列表存储）
  val borrowRecords = mutable.ListBuffer[BorrowRecord](
    BorrowRecord("BR001", "R001", "B002", "2025-10-01", "2025-10-15", 0),
    BorrowRecord("BR002", "R001", "B001", "2025-10-05", "2025-10-19", 1)
  )

  // 3. 辅助函数
  /** 生成唯一ID（前缀+时间戳） */
  def generateId(prefix: String): String = s"$prefix${System.currentTimeMillis()}"

  /** 检查图书是否可借（库存>0） */
  def isBookAvailable(bookId: String): Boolean = {
    books.get(bookId).exists(_.availableCopies > 0)
  }

  // 4. 核心功能实现
  /** 读者登录（do-while：至少尝试1次，最多3次） */
  def login(): Option[Reader] = {
    var reader: Option[Reader] = None
    var attempts = 0
    val maxAttempts = 3  // 最大登录尝试次数

    do {
      attempts += 1
      // 模拟输入读者ID（实际场景为控制台输入，此处随机选择）
      val testReaderIds = readers.keys.toList
      val inputId = if (attempts == 1) "R001" else testReaderIds(Random.nextInt(testReaderIds.size))

      reader = readers.get(inputId)
      if (reader.isDefined) {
        println(s"登录成功！欢迎 ${reader.get.name}（${reader.get.id}）")
        // 提醒未缴罚款
        if (reader.get.unpaidFines > 0) {
          println(f"提醒：您有未缴罚款 ${reader.get.unpaidFines}%.2f 元")
        }
      } else {
        println(s"读者ID $inputId 不存在，请重新输入")
      }
    } while (reader.isEmpty && attempts < maxAttempts)  // 未成功且未超次数则继续

    reader
  }

  /** 图书查询（do-while：至少查询1次，没结果则继续） */
  def searchBooks(): List[Book] = {
    var results = List.empty[Book]
    var continueSearch = true

    do {
      // 模拟查询关键词（实际场景为用户输入，此处随机选择）
      val keywords = List("编程", "数据", "机器", "计算机", "算法")
      val keyword = keywords(Random.nextInt(keywords.size))
      println(s"\n查询关键词：'$keyword'")

      // 执行查询：标题或作者包含关键词
      results = books.values.filter { book =>
        book.title.contains(keyword) || book.author.contains(keyword)
      }.toList

      // 显示查询结果
      println(s"找到 ${results.size} 本相关图书：")
      results.foreach { book =>
        println(f"[${book.id}] ${book.title} (${book.author}) - 可借: ${book.availableCopies}/${book.totalCopies}")
      }

      // 没找到结果则继续查询
      continueSearch = results.isEmpty
    } while (continueSearch)

    results
  }

  /** 图书借阅（while：最多借5本，未超上限则继续） */
  def borrowBooks(reader: Reader, availableBooks: List[Book]): Int = {
    var borrowedCount = 0
    val maxBorrow = 5  // 最大借阅数量
    var continue = true

    // 前置检查：未缴罚款超50元，禁止借阅
    if (reader.unpaidFines > 50) {
      println(s"\n无法借阅：您的未缴罚款 ${reader.unpaidFines} 元超过50元上限")
      return 0
    }

    // while循环：控制借阅数量
    while (continue && borrowedCount < maxBorrow && availableBooks.nonEmpty) {
      // 筛选当前可借的图书（排除已无库存的）
      val available = availableBooks.filter(b => books(b.id).availableCopies > 0)

      if (available.nonEmpty) {
        val selectedBook = available.head  // 选择第一本可借图书
        println(s"\n正在借阅《${selectedBook.title}》...")

        // 更新图书库存（可借数量-1）
        books(selectedBook.id).availableCopies -= 1

        // 创建借阅记录
        val borrowDate = "2025-10-20"
        val dueDate = "2025-11-03"  // 借阅期限14天
        borrowRecords += BorrowRecord(
          generateId("BR"),
          reader.id,
          selectedBook.id,
          borrowDate,
          dueDate,
          0  // 初始续借次数0
        )

        borrowedCount += 1
        println(s"借阅成功！到期日：$dueDate")

        // 模拟用户选择：最多再借1本（实际场景为控制台输入）
        continue = borrowedCount < 2
      } else {
        println("\n没有可借的图书了")
        continue = false  // 无库存，退出循环
      }
    }

    borrowedCount
  }

  /** 图书归还与罚款计算（while：有未还记录则继续） */
  def returnBooks(reader: Reader): Int = {
    var returnedCount = 0
    var continue = true

    // 获取该读者的未归还记录
    val readerRecords = borrowRecords.filter(br =>
      br.readerId == reader.id && br.returnDate.isEmpty
    )

    // 无未还记录，直接返回
    if (readerRecords.isEmpty) {
      println("\n您没有需要归还的图书")
      return 0
    }

    // while循环：处理每本未还图书
    while (continue && returnedCount < readerRecords.size) {
      val record = readerRecords(returnedCount)
      val book = books(record.bookId)

      println(s"\n正在归还《${book.title}》...")

      // 模拟超期天数（0-20天随机）
      val overDays = Random.nextInt(21)
      if (overDays > 0) {
        // 计算罚款（每天0.5元，最多15元）
        val dailyFine = 0.5
        val maxFine = 15.0
        val fine = math.min(overDays * dailyFine, maxFine)

        // 累加未缴罚款
        reader.unpaidFines += fine
        println(f"图书已超期 $overDays 天，需缴纳罚款 $fine%.2f 元")
        println(f"当前总未缴罚款：${reader.unpaidFines}%.2f 元")
      } else {
        println("图书按时归还，无需缴纳罚款")
      }

      // 更新记录和库存
      record.returnDate = Some("2025-10-20")  // 标记归还日期
      book.availableCopies += 1  // 库存+1

      returnedCount += 1

      // 模拟用户选择：最多再还1本（实际场景为控制台输入）
      continue = returnedCount < 1
    }

    returnedCount
  }

  // 5. 系统主流程
  println("===== 校园图书借阅系统 =====")

  // 登录流程
  val currentReader = login()
  if (currentReader.isEmpty) {
    println("登录失败，程序退出")
  } else {
    var running = true  // 控制主菜单循环

    // 主菜单while循环：系统运行期间持续显示
    while (running) {
      println("\n===== 功能菜单 =====")
      println("1. 图书查询与借阅")
      println("2. 图书归还")
      println("3. 退出系统")

      // 模拟选择功能（实际场景为控制台输入）
      val choice = if (borrowRecords.exists(br =>
        br.readerId == currentReader.get.id && br.returnDate.isEmpty
      )) 2 else 1  // 有未还记录则默认选归还，否则选借阅

      println(s"您选择了功能 $choice")

      // 功能分支处理
      choice match {
        case 1 =>
          val foundBooks = searchBooks()
          val borrowed = borrowBooks(currentReader.get, foundBooks)
          println(s"\n本次共借阅 $borrowed 本图书")

        case 2 =>
          val returned = returnBooks(currentReader.get)
          println(s"\n本次共归还 $returned 本图书")

        case 3 =>
          println("感谢使用，再见！")
          running = false  // 修改条件，退出主循环

        case _ =>
          println("无效选择，请重新选择")
      }
    }
  }
}